<template>


</template>

<script setup name="Home">
import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import Stats from 'three/examples/jsm/libs/stats.module.js'
const scene = new THREE.Scene();

//透视摄像机（模拟人眼）
const camera = new THREE.PerspectiveCamera(75,
    window.innerWidth / window.innerHeight,
    0.1, 1000);

const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);

//渲染器开启阴影支持
renderer.shadowMap.enabled=true;
document.body.appendChild(renderer.domElement);

camera.position.z = 5;
let cube;

let cubeArr=[]
//创建5个颜色位置 大小随机的立方体
function createRandomCube(){

    const list=[];
    for(let i=0;i<5;i++){
        list.push({
            col:`rgb(${Math.floor(Math.random()*256)},
            ${Math.floor(Math.random()*256)},${Math.floor(Math.random()*256)})`,
             width:Math.floor(Math.random()*(3-1+1)+1),
             height:Math.floor(Math.random()*(3-1+1)+1),
             deep:Math.floor(Math.random()*(3-1+1)+1),
             x:Math.floor(Math.random()*(5- -5+1)-5),
             y:Math.floor(Math.random()*(5- -5+1)-5),
             y:Math.floor(Math.random()*(5- -5+1)-5),
        })
    }
    list.forEach(({col,width,heigth,deep,x,y,z},index)=>{
        const geometry = new THREE.BoxGeometry(width, heigth, deep);
        const material = new THREE.MeshBasicMaterial({ color: col });
        cube = new THREE.Mesh(geometry, material);
        cube.userData.ind=index;
        cube.position.set(x,y,z);
        scene.add(cube);
        cubeArr.push(cube);
    })
}
//绘制立方体
function createCube() {
    //绘制6个面颜色不同的立方体 顺序 x轴正负  y轴正负 z轴正负
     const colors = ['red', 'green', 'blue', 'pink','orange','white']
     const meterialArr= colors.map(color=>{
        return   new THREE.MeshBasicMaterial({ color });
     })
    //几何图形
    const geometry = new THREE.BoxGeometry(1, 1, 1);
    //材质
    const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });

    
    //创建物体
    cube = new THREE.Mesh(geometry, meterialArr);
    //加入场景中
    scene.add(cube);
    cube.position.x = 3
    const axes = new THREE.AxesHelper(3);
    cube.add(axes)
}
//创建球体
function createSphere(){
    //three 中所有的网格物体都是有三角形组成
    //参数1 半径 参数2水平的分段数(分几个坐标点) 参数
    const geometry = new THREE.SphereGeometry( 2, 32, 16 );
    //基础网格材质
		const material = new THREE.MeshBasicMaterial( { color: 'red' } );
		const sphere = new THREE.Mesh( geometry, material );
		scene.add( sphere );
}
//坐标轴 红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.
function createAxesHelper() {
    const axesHelper = new THREE.AxesHelper(5);
    scene.add(axesHelper)

}

let controls;
//轨道控制器改变摄像机的位置
function createOrbitControls() {
    //参数1 控制的摄像机
    //参数2 鼠标交互的标签(监听canvas画布鼠标滑动交互)
    controls = new OrbitControls(camera, renderer.domElement);
    //  controls.update();
}

function bindDBClick(){
    window.addEventListener("dblclick",(event)=>{
    //光线投射
    const raycaster = new THREE.Raycaster();
    const pointer = new THREE.Vector2();
    // 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)

    pointer.x = ( event.clientX / window.innerWidth ) * 2 - 1;
    pointer.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
    // 通过摄像机和鼠标位置更新射线
	raycaster.setFromCamera( pointer, camera );
    // 计算物体和射线的焦点 要让摄像机到鼠标垫传过去一条线 与哪些3D物体交互计算
    //顺序是有远到近
	const intersects = raycaster.intersectObjects(cubeArr );
    if(intersects.length==0){
        return
    }

    const cube = intersects[0].object;
    if(!cube) return
    const index = cube.userData.ind;
      cube.geometry.dispose();
        cube.material.dispose();
        scene.remove(cube);
        cubeArr.splice(index,1);
      //  cubeArr.shift();
        // const cube = cubeArr[0];
        // if(!cube) return
        // //先删除内存
        // cube.geometry.dispose();
        // cube.material.dispose();
        // scene.remove(cube);
        //cubeArr.shift();
    });
}
let stats ;
let speed=0.01


function resize() {
    //监听窗口尺寸的改变
    window.addEventListener('resize', () => {
        //设置画布的宽高
        renderer.setSize(window.innerWidth, window.innerHeight);
        //更新摄像机矩阵空间  让摄像机重新计算每个像素点位置
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
    })
}

//性能监控
function createStats(){
    stats = new Stats();
    stats.setMode(0);//0 每帧刷新帧数  1每帧用时 2 内存占用
    stats.domElement.style.position = 'absolute'
    stats.domElement.style.left = '0px'
    stats.domElement.style.top = '0px'
    document.body.appendChild(stats.domElement)
}
//改变物体的位置 参考的是世界轴
//cube.position.x = 3
//cube.position.y=10
//cube.position.set(10,0,-10)


//旋转 原地的值Euler 欧拉角对象 描述的绕着x，y，z轴的旋转
//从轴线的正方向来看物体 物体是绕着自身轴线逆时针旋转 这句话怎么理解  世界轴有一个xyz 然后物体本身也有一个xyz 旋转式按照自身的xyz轴旋转的
//const axes = new THREE.AxesHelper( 3 );
//cube.add(axes)
//cube.rotation.x = Math.PI / 4

//缩放 中心店㐑 向某个轴两边拉伸或者缩小
//cube.scale.y=2

let mesh;

//使用球体+标准网络材质 来对灯光做出反应
function createQiu(){
    //如果没有光 那么就是黑色
    const geometry = new THREE.SphereGeometry( 2, 32, 16 );
    const material = new THREE.MeshStandardMaterial({color:"red"})
    mesh = new THREE.Mesh( geometry, material );
    mesh.castShadow=true;
    scene.add( mesh );
}

//平行光 模拟的是太阳光
function createLight(){
    //平行光 光的颜色 强度
    const directionLight=new THREE.DirectionalLight(0xffffff,5);
    directionLight.position.set(3,3,3)
    scene.add( directionLight );

    //光源辅助对象 用线段模拟光源位置 第二个参数是辅助线的宽高
    const directionalLightHelper=new THREE.DirectionalLightHelper(directionLight,3)
    scene.add( directionalLightHelper );
}

function createFloor(){
    const geometry = new THREE.PlaneGeometry( 10,10 );
    //第二额参数 渲染2个面   roughness:0.5 粗糙度  0反光  粗糙的话就反光  const material = new THREE.MeshBasicMaterial({color:0xffff00,side:THREE.DoubleSide})
    const material = new THREE.MeshStandardMaterial({color:0xffffff,side:THREE.DoubleSide,roughness:0.5})
    const plane = new THREE.Mesh( geometry, material );
    plane.receiveShadow=true;
    scene.add( plane );
    plane.rotation.x= -Math.PI / 2;
    plane.position.y=-1;

}
  //环境光 照亮所有物体的所有面 没有方向 没有阴暗面 没有光斑
function createAmbientLight(){
    const light=new THREE.AmbientLight(0xffffff,1);
    scene.add( light );
}

//点光源 有位置  有方向  会阴暗面 会光斑
function createPointLight(){
    //光源颜色  光照强度  光最远距离
    const pointLight=new THREE.PointLight(0xffffff,10,100);
    pointLight.position.set(3,3,3)
    scene.add( pointLight );
        //光源辅助对象 用线段模拟光源位置 第二个参数是辅助线的宽高
        const PointLightHelper=new THREE.PointLightHelper(pointLight,1)
    scene.add( PointLightHelper );
}
let helper;
//聚光灯
function createSpotLight(){
    //参数3 聚光灯能达到多远 参数4 聚光灯发送的角度（默认是Math.PI/3）参数5 光斑周围虚的程度（0-1） 参数6  光照衰减亮 随着距离越远 在值的基础上就越弱
    const spotLight=new THREE.SpotLight(0xffffff,10,100,Math.PI/6,0.5,1);
    spotLight.position.set(3,3,3);
   
    //加载图片--纹理对象 给聚光灯设置一个贴图  让灯打出（颜色+图片）图案
   // spotLight.map=new THREE.TextureLoader().load('src/assets/avatar.png')
    scene.add( spotLight );
    helper=new THREE.SpotLightHelper(spotLight)
//  此时辅助线不动  需要在动画中更新
  scene.add( helper );
    //当物体移动的试试 聚光灯也随着移动  聚光灯的目标是在世界原点 0,0,0
    spotLight.target=mesh;
}

//灯光阴影
//渲染器计算阴影
//灯光产生阴影
//物体产生阴影
//地面接收阴影计算
function createShadow(){
    //平行光 光的颜色 强度
    const directionLight=new THREE.DirectionalLight(0xffffff,5);
    directionLight.position.set(3,3,3)
    //光源设置产生阴影
    directionLight.castShadow=true;
    scene.add( directionLight );
    directionLight.target=mesh;
    //光源辅助对象 用线段模拟光源位置 第二个参数是辅助线的宽高
     helper=new THREE.DirectionalLightHelper(directionLight,3)
    scene.add( helper );
}
function animate() {
    //根据浏览器刷新帧率 默认1s60次 不断递归调用此渲染函数 为了让render渲染最新的画面
    requestAnimationFrame(animate);
    controls.update();
    //cube.rotation.z+=0.01
    // cubeArr.forEach(cube=>{
    //     cube.rotation.y+=0.01
    // })
    stats.update()
    mesh.position.x+=speed;

    if(mesh.position.x>5){
        speed=-0.01;
    }else if(mesh.position.x<=0){
        speed=0.01;
    }
    helper.update();
    
    renderer.render(scene, camera)
}
resize();
createStats();
//createRandomCube();
//createCube()
createAxesHelper();
createOrbitControls();
 //createSphere();
bindDBClick();
createQiu();
//createLight();
createFloor();
//createPointLight();
//createAmbientLight();
//createSpotLight();
createShadow()
animate();

</script>
<style scoped></style>